package zero.tech.games.pdk.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import zero.tech.core.ZeroContext;
import zero.tech.core.data.Resp;
import zero.tech.games.common.Code;
import zero.tech.games.common.TUserAccountUtil;
import zero.tech.games.common.WaterMode;
import zero.tech.games.entity.games.Club;
import zero.tech.games.entity.user.TUserAccount;
import zero.tech.games.logic.common.Room;
import zero.tech.games.logic.data.RoomStatus;
import zero.tech.games.logic.data.consts.LOGICCMD;
import zero.tech.games.logic.service.api.ILogicService;
import zero.tech.games.logic.util.LogicUtil;
import zero.tech.games.logic.util.PckUtil;
import zero.tech.games.pdk.data.PdkConfig;
import zero.tech.games.pdk.data.PdkGameBase;
import zero.tech.games.pdk.data.PdkTimer;
import zero.tech.games.pdk.data.consts.PDKCMD;
import zero.tech.games.pdk.data.consts.PdkMode;
import zero.tech.games.pdk.data.entity.Card;
import zero.tech.games.pdk.data.entity.DispatchData;
import zero.tech.games.pdk.data.entity.PdkOut;
import zero.tech.games.pdk.data.entity.PlayerData;
import zero.tech.games.pdk.service.api.IPdkService;
import zero.tech.wsnet.controller.LogicController;
import zero.tech.wsnet.data.Message;

public class RoomUtil {
	public static final int HEISANID=403;
	public static final int HONGSHI=310;
	public static void checkGameStart(Room room) {
		IPdkService pdkService=ZeroContext.getInstance(IPdkService.class);
		PdkConfig pdkConfig = (PdkConfig) room.getGameConfig();
		PdkTimer pdkTimer=(PdkTimer) room.getTimer();
		int bird=pdkConfig.getBird();
		int room_status=room.getRoom_status();
		if(bird==1&&room_status==RoomStatus.DEFAULT) {
			//打鸟开启
			List<LogicController> birdPeopers=LogicUtil.birdPeopers(room);
			if(birdPeopers.size()==room.getMax_player()&&room.getAllControllers().size()==room.getMax_player()) {
				pdkService.gameStart(room);
			}
		}else {
			//打鸟未开启
			List<LogicController> readyPeopers=LogicUtil.readyPeopers(room);
			if(readyPeopers.size()==room.getMax_player()&&room.getAllControllers().size()==room.getMax_player()) {
				pdkService.gameStart(room);
			}else {
				if(room_status==RoomStatus.WAIT_NEXT_ROUND) {
					ILogicService logicService=ZeroContext.getInstance(ILogicService.class);
					//自动准备
					long now=System.currentTimeMillis();
					long lastBeginToReadyTime=pdkTimer.lastBeginToReadyTime;
					List<LogicController> notReadyPeopers=LogicUtil.notReadyPeopers(room);
					if(now-lastBeginToReadyTime>=pdkConfig.getResult_wait_time()*1000) {
						for(LogicController notReadyPeople:notReadyPeopers) {
							logicService.reqReady(room,notReadyPeople);
						}
					}
				}
			}
		}
	}

	public static void notifyNextPlayer(Room room) {
		PdkGameBase pdkGameBase=(PdkGameBase) room.getGameBase();
		PdkTimer pdkTimer = (PdkTimer) room.getTimer();
		int dispatch_uid=pdkGameBase.getDispatch_uid();
		int next_uid=LogicUtil.getNextPosByUid(room,dispatch_uid);
		pdkGameBase.setDispatch_uid(next_uid);
		pdkTimer.lastDispatchTime=System.currentTimeMillis();
		LogicUtil.broadRoomAllControllersInclude(room, Message.build(PDKCMD.NOTIFY_CHANGE_PLAYER, Resp.build(Code.OK, "换人",PackageUtil.packageNotifyChangePlayer(room,dispatch_uid))));
		
//		DispatchData pre=pdkGameBase.getPre();
//		if(pre.getUid()!=next_uid) {
//			//下家需要跟牌,检查下家要不起直接打
////			PdkConfig pdkConfig=(PdkConfig) room.getGameConfig();
////			PlayerData playerData = pdkGameBase.getPlayers().get(next_uid);
////			List<Card> hands=new ArrayList<>();
////			hands.addAll(playerData.getHands().values());
////			PdkOut auto=CardUtil.autoFollow(hands,pre.getPdkOut(),pdkConfig);
////			if(auto==null) {
////				LogicController controller = room.getAllControllers().get(next_uid);
////				dispatch(room, controller, null);
////				return;
////			}
//			//下家跟手出牌,检查剩下的牌能否一手出完
//			PdkOut pdkOut= leftShowHandPdkOutFollow(room, next_uid,pre.getPdkOut());
//			if(pdkOut!=null) {
//				//直接打
//				LogicController controller = room.getAllControllers().get(next_uid);
//				dispatch(room, controller, pdkOut);
//				return;
//			}
//		}else {
//			//下家先手出牌,检查剩下的牌能否一手出完
//			PdkOut pdkOut= leftShowHandPdkOut(room, next_uid);
//			if(pdkOut!=null) {
//				//直接打
//				LogicController controller = room.getAllControllers().get(next_uid);
//				dispatch(room, controller, pdkOut);
//				return;
//			}
//		}
		
	}

	public static void autoDispatch(Room room) {
		PdkGameBase pdkGameBase=(PdkGameBase) room.getGameBase();
		DispatchData pre=pdkGameBase.getPre();
		if(pre==null) {
			autoFirstDispatch(room,pdkGameBase);
		}else {
			autoFollowDispatch(room,pdkGameBase,pre);
		}
	}

	private static void autoFirstDispatch(Room room, PdkGameBase pdkGameBase) {
		//检测剩下的手牌能否一手出
		int dispatch_uid=pdkGameBase.getDispatch_uid();
		int next_uid=LogicUtil.getNextPosByUid(room,dispatch_uid);
		PlayerData playerData=pdkGameBase.getPlayers().get(dispatch_uid);
		PlayerData nextPlayerData = pdkGameBase.getPlayers().get(next_uid);
		List<Card> hands=new ArrayList<>();
		hands.addAll(playerData.getHands().values());
		if(nextPlayerData.getHands().size()==1) {
			//下家报单(打最大)
			Collections.sort(hands,new Comparator<Card>() {
				@Override
				public int compare(Card o1, Card o2) {
					return o2.getCardNum()-o1.getCardNum();
				}
			});
		}else {
			Collections.sort(hands,new Comparator<Card>() {
				@Override
				public int compare(Card o1, Card o2) {
					int result= o1.getCardNum()-o2.getCardNum();
					if(result==0) {
						result= o2.getCardColor()-o1.getCardColor();
					}
					return result;
				}
			});
		}
		List<Card> auto=new ArrayList<>();
		auto.add(hands.get(0));
		PdkOut pdkOut = new PdkOut(CardsType.DAN, auto.get(0).getCardNum(), auto);
		LogicController controller=room.getAllControllers().get(dispatch_uid);
		dispatch(room, controller, pdkOut);
	}


	private static void autoFollowDispatch(Room room, PdkGameBase pdkGameBase, DispatchData pre) {
		int pre_uid=pre.getUid();
		int dispatch_uid=pdkGameBase.getDispatch_uid();
		if(pre_uid==dispatch_uid) {
			autoFirstDispatch(room, pdkGameBase);
		}else {
			PdkOut pdkOut=pre.getPdkOut();
			int cardstype=pdkOut.getCardstype();
			int next_uid=LogicUtil.getNextPosByUid(room,dispatch_uid);
			PlayerData nextPlayerData = pdkGameBase.getPlayers().get(next_uid);
			PlayerData playerData=pdkGameBase.getPlayers().get(dispatch_uid);
			List<Card> hands=new ArrayList<>();
			hands.addAll(playerData.getHands().values());
			PdkConfig pdkConfig=(PdkConfig) room.getGameConfig();
			int bichu=1;
			LogicController controller=room.getAllControllers().get(dispatch_uid);
			if(bichu==0) {
				dispatch(room, controller, null);
				return;
			}
			//要的起必要,跟牌
			PdkOut auto=null;
			if(nextPlayerData.getHands().size()==1&&cardstype==CardsType.DAN) {
				//下家报单,如果跟的是单张,需要出最大牌
				Collections.sort(hands,new Comparator<Card>() {
					@Override
					public int compare(Card o1, Card o2) {
						return o2.getCardNum()-o1.getCardNum();
					}
				});
				Card max=hands.get(0);
				if(max.getCardNum()>pdkOut.getMax()) {
					List<Card> cards=new ArrayList<>();
					cards.add(max);
					auto=new PdkOut(cardstype, max.getCardNum(), cards);
				}
			}else {
				auto=CardUtil.autoFollow(hands,pdkOut,pdkConfig);
			}
			if(auto==null) {
				dispatch(room, controller, null);
				return;
			}
			dispatch(room, controller, auto);
		}		
	}

	public static boolean hascards(Room room, LogicController controller, List<Integer> cardIds) {
		PdkGameBase pdkGameBase = (PdkGameBase) room.getGameBase();
		int uid=controller.getId();
		PlayerData playerData =pdkGameBase.getPlayers().get(uid);
		Map<Integer,Card> cards=playerData.getHands();
		for(Integer cardId:cardIds) {
			if(!cards.containsKey(cardId.intValue())) {
				return false;
			}
		}
		return true;
	}

	public static List<Card> selectCardsInHand(Room room, LogicController controller, List<Integer> cardIds) {
		List<Card> list=new ArrayList<>();
		int uid=controller.getId();
		PdkGameBase pdkGameBase =(PdkGameBase) room.getGameBase();
		PlayerData playerData = pdkGameBase.getPlayers().get(uid);
		for(Integer cardId:cardIds) {
			list.add(playerData.getHands().get(cardId));
		}
		return list;
	}

	public static void reqDispatchCard(Room room, LogicController controller, List<Integer> cardIds) {
		boolean hascards=RoomUtil.hascards(room,controller,cardIds);
		if(!hascards) {
			controller.getWebClient().sendMessage(Message.build(PDKCMD.RES_DISPATCHCARD, Resp.build(Code.PARAM_ERROR, "参数错误")));
			return;
		}
		int uid=controller.getId();
		PdkGameBase pdkGameBase=(PdkGameBase) room.getGameBase();
		List<Card> cards=RoomUtil.selectCardsInHand(room,controller,cardIds);
		List<Card> hands=new ArrayList<>();
		hands.addAll(pdkGameBase.getPlayers().get(uid).getHands().values());
		PdkConfig pdkConfig = (PdkConfig) room.getGameConfig();
		DispatchData pre=pdkGameBase.getPre();
		PdkOut pdkOut=CardUtil.parsePdkOut(cards,hands,pdkConfig,pre,controller);
		if(pdkOut==null) {
			//牌型不合法,检测不出
			controller.getWebClient().sendMessage(Message.build(PDKCMD.RES_DISPATCHCARD, Resp.build(Code.PAIXIN_ERROR, "牌型错误")));
			return;
		}

		if(pre==null) {
			if(pdkConfig.getShoulunheisan()==1&&room.getRoom_times()==1) {
				boolean hasheisaninhand=hei3InCardList(hands);
				if(hasheisaninhand) {
					//首轮黑三必出
					List<Card> outs=pdkOut.getOuts();
					boolean hasheisan=false;
					for(Card card:outs) {
						if(card.getCardId()==HEISANID) {
							hasheisan=true;
							break;
						}
					}
					if(!hasheisan) {
						controller.getWebClient().sendMessage(Message.build(PDKCMD.RES_DISPATCHCARD, Resp.build(Code.SHOULUNHEISAN, "首轮黑三必出")));
						return;
					}
				}
			}
			firstDispatch(room,controller,pdkOut);
		}else {
			int next_uid=LogicUtil.getNextPosByUid(room,uid);
			PlayerData nextPlayerData = pdkGameBase.getPlayers().get(next_uid);
			if(nextPlayerData.getHands().size()==1&&pdkOut.getCardstype()==CardsType.DAN) {
				//如果自己打的不是最大的且打牌比下家牌小则需要包牌
				Collections.sort(hands,new Comparator<Card>() {

					@Override
					public int compare(Card o1, Card o2) {
						return o2.getCardNum()-o1.getCardNum();
					}
				});
				
				int max=hands.get(0).getCardNum();
				if(pdkOut.getMax()<max) {
					//下家报单,必须打最大的
					controller.getWebClient().sendMessage(Message.build(PDKCMD.RES_DISPATCHCARD, Resp.build(Code.PAIXIN_ERROR, "下家报单了,必须打最大的")));
					return;
				}
			}
			followDispatch(room,controller,pre,pdkOut);
		}
	}

	private static void firstDispatch(Room room, LogicController controller, PdkOut pdkOut) {
		dispatch(room, controller, pdkOut);
	}

	private static void followDispatch(Room room, LogicController controller, DispatchData pre, PdkOut pdkOut) {
		int uid=controller.getId();
		if(pre.getUid()==uid) {
			firstDispatch(room,controller,pdkOut);
		}else {
			int cardstype=pre.getPdkOut().getCardstype();
			int max=pre.getPdkOut().getMax();
			if(pdkOut.getCardstype()==CardsType.ZHA_DAN) {
				if(pre.getPdkOut().getCardstype()==CardsType.ZHA_DAN&&pdkOut.getMax()<=max) {
					//出牌要不起
					controller.getWebClient().sendMessage(Message.build(PDKCMD.RES_DISPATCHCARD, Resp.build(Code.CANT_FOLLOW, "要不起")));
					return;
				}
			}else {
				if(pdkOut.getCardstype()!=cardstype) {
					//出牌牌型不合法
					controller.getWebClient().sendMessage(Message.build(PDKCMD.RES_DISPATCHCARD, Resp.build(Code.PAIXIN_ERROR, "参数错误")));
					return;
				}
				if(pdkOut.getMax()<=max) {
					//出牌要不起
					controller.getWebClient().sendMessage(Message.build(PDKCMD.RES_DISPATCHCARD, Resp.build(Code.CANT_FOLLOW, "要不起")));
					return;
				}
			}
			dispatch(room, controller, pdkOut);
		}		
	}

	public static void dispatch(Room room, LogicController controller, PdkOut pdkOut) {
		int uid=controller.getId();
		PdkGameBase pdkGameBase = (PdkGameBase) room.getGameBase();
		DispatchData dispatchData=new DispatchData(uid);
		PlayerData playerData = pdkGameBase.getPlayers().get(uid);
		if(pdkOut!=null) {
			if(pdkGameBase.getLastBombUid()!=null&&uid!=pdkGameBase.getLastBombUid()) {
				PlayerData lastBombPlayerData=pdkGameBase.getPlayers().get(pdkGameBase.getLastBombUid());
				lastBombPlayerData.setZhadan_count(lastBombPlayerData.getZhadan_count()-1);
			}else {
				pdkGameBase.setLastBombUid(null);
			}
			pdkGameBase.setPre(new DispatchData(uid,pdkOut));
			List<Card> cards=pdkOut.getOuts();
			for(Card card:cards) {
				Card tmp=playerData.getHands().remove(card.getCardId());
				playerData.getOuts().add(tmp);
			}
			dispatchData.setPdkOut(pdkOut);
			if(pdkOut.getCardstype()==CardsType.ZHA_DAN) {
				playerData.setZhadan_count(playerData.getZhadan_count()+1);
				pdkGameBase.setLastBombUid(uid);
			}
		}
		pdkGameBase.getLast_dispatchs().put(uid, dispatchData);//最后一次操作数据
		pdkGameBase.getDispatch_datas().add(dispatchData);//战绩使用
		LogicUtil.broadRoomAllControllersInclude(room, Message.build(PDKCMD.NOTIFY_DISPATCH_CARD, Resp.build(Code.OK, "出牌",PackageUtil.packageNotifyDispatchCard(room,dispatchData))));
		
		//检查游戏结束
		IPdkService pdkService=ZeroContext.getInstance(IPdkService.class);
		boolean gameOver=pdkService.checkGameOver(room,controller);
		if(gameOver) {
			pdkService.gameOver(room,controller);
		}else {
			notifyNextPlayer(room);
		}
	}


	public static void pass(Room room, LogicController controller) {
		PdkConfig pdkConfig=(PdkConfig) room.getGameConfig();
		PdkGameBase pdkGameBase = (PdkGameBase) room.getGameBase();
		int dispatch_uid=pdkGameBase.getDispatch_uid();
		DispatchData pre = pdkGameBase.getPre();
		if(pre==null||pre.getUid()==dispatch_uid) {
			controller.getWebClient().sendMessage(Message.build(PDKCMD.RES_DISPATCHCARD, Resp.build(Code.MUST_DISPATCH, "必须出牌")));
			return;
		}
		PdkOut pdkOut=pre.getPdkOut();
		PlayerData playerData=pdkGameBase.getPlayers().get(dispatch_uid);
		List<Card> hands=new ArrayList<>();
		hands.addAll(playerData.getHands().values());
		PdkOut auto=CardUtil.autoFollow(hands,pdkOut,pdkConfig);
		if(auto!=null) {
			controller.getWebClient().sendMessage(Message.build(PDKCMD.RES_DISPATCHCARD, Resp.build(Code.MUST_DISPATCH, "必须出牌")));
			return;
		}

		dispatch(room, controller, null);
	}

	public static boolean hei3InCardList(List<Card> hands) {
		for(Card card:hands) {
			if(card.getCardId()==RoomUtil.HEISANID) {
				return true;
			}
		}
		return false;
	}

	public static boolean hong10InCardList(List<Card> hands) {
		for(Card card:hands) {
			if(card.getCardId()==RoomUtil.HONGSHI) {
				return true;
			}
		}
		return false;
	}


	public static void autoOperate(Room room) {
		PdkConfig pdkConfig=(PdkConfig) room.getGameConfig();
		PdkTimer pdkTimer=(PdkTimer) room.getTimer();
		PdkGameBase pdkGameBase = (PdkGameBase) room.getGameBase();
		int dispatch_uid=pdkGameBase.getDispatch_uid();
		long now=System.currentTimeMillis();
		long lastDispatchTime=pdkTimer.lastDispatchTime;
//		DispatchData pre=pdkGameBase.getPre();
//		if(pre==null||(pre!=null&&pre.getUid()==dispatch_uid)) {
//			//第一手出牌,检查剩下的牌能否一手出完
//			PdkOut pdkOut= leftShowHandPdkOut(room, dispatch_uid);
//			if(pdkOut!=null) {
//				//直接打
//				LogicController controller = room.getAllControllers().get(dispatch_uid);
//				dispatch(room, controller, pdkOut);
//				return;
//			}
//		}
		
		
//		if(pre!=null&&pre.getUid()!=dispatch_uid) {
//			//检查要不起直接打
//			PlayerData playerData = pdkGameBase.getPlayers().get(dispatch_uid);
//			List<Card> hands=new ArrayList<>();
//			hands.addAll(playerData.getHands().values());
//			PdkOut auto=CardUtil.autoFollow(hands,pre.getPdkOut(),pdkConfig);
//			if(auto==null) {
//				LogicController controller = room.getAllControllers().get(dispatch_uid);
//				dispatch(room, controller, null);
//				return;
//			}
//		}
		
		
		if(pdkConfig.getAuto_deposit()>0) {
			if(pdkGameBase.getAuto_deposit().containsKey(dispatch_uid)) {
				if(now-lastDispatchTime>=3*1000) {
					//当前打牌玩家已经被托管了
					RoomUtil.autoDispatch(room);
				}
			}else {
				if(now-lastDispatchTime>=pdkConfig.getAuto_deposit()*1000) {
					//长时间不打牌,自动托管
					pdkGameBase.getAuto_deposit().put(dispatch_uid, now);
					//广播某人进入托管
					LogicUtil.broadRoomAllControllersInclude(room, Message.build(LOGICCMD.NOTIFY_ENTER_AUTODEPOSIT, Resp.build(Code.OK, "进入托管",PckUtil.packageNotifyEnterAutoDeposit(dispatch_uid,now))));
				}
			}
		}		
	}

	public static Integer findMaxValInMap(Map<Integer, Integer> birds) {
		Integer key=null;
		int max=0;
		for(Entry<Integer,Integer>entry:birds.entrySet()) {
			if(entry.getValue()>=max) {
				max=entry.getValue();
				key=entry.getKey();
			}
		}
		return key;
	}

	public static boolean checkMoneyEnoughNextRound(Room room, LogicController logicController) {
		Club club=room.getClub();
		if(club!=null) {
			long gold=logicController.getGold();
			PdkConfig pdkConfig = (PdkConfig) room.getGameConfig();
			int room_status=room.getRoom_status();
			if(room_status==RoomStatus.DEFAULT) {
				Long admission_fee=pdkConfig.getAdmission_fee();
				if(gold>=admission_fee) {
					return true;
				}
			}else {
				int water_mode=pdkConfig.getWater_mode();
				long need_aa=0L;
				if(water_mode==WaterMode.AA) {
					//需要预留AA抽水的钱
					need_aa=pdkConfig.getWater_num();
				}
				//检查钱是否足够
				int card_length=pdkConfig.getPdk_mode()==PdkMode.MODE15?15:16;
				long base_score=pdkConfig.getBase_score();
				int hongshi=pdkConfig.getHongshi();//处理红十
				int need_score=0;
				if(pdkConfig.getBird()==1) {
					//计算打鸟分数
					int bird_need=2*pdkConfig.getBird_max()*(pdkConfig.getMax_player()-1);//多个并列第一名
					need_score+=bird_need;//加打鸟分数
				}
				need_score+=4*10;//4个炸弹
				if(hongshi==1) {
					need_score+=card_length*2+5;//春天红十加5分
				}else if(hongshi==2) {
					need_score+=card_length*2*2;//春天红十加5分
				}else {
					need_score+=card_length;
				}
				long need=need_score*base_score+need_aa;
				if(gold>=need) {
					return true;
				}
			}
			return false;
		}else {
			int uid=logicController.getId();
			TUserAccountUtil userAccountUtil=ZeroContext.getInstance(TUserAccountUtil.class);
			TUserAccount userAccount=userAccountUtil.getUserAccount(uid);
			PdkConfig pdkConfig =(PdkConfig) room.getGameConfig();
			int water_mode=pdkConfig.getWater_mode();
			long water_num=pdkConfig.getWater_num();
			if(water_mode==WaterMode.AA) {
				if(userAccount.getDiamond()>=water_num) {
					return true;
				}
			}
			return false;
//			return true;
		}
	}
}
